1 1. Introduction

1.1 Description of Data

This dataset was obtained from Kaggle.This dataset contains health and risk factors related to the heart disease. The dataset involves parameters such as diabetes,stress level, smoking,age,gender among others to analyse the risk of heart disease and contribute effectively to health research. This dataset can be used to study the factors that contribute to the development of heart diseases.

1.2 Purpose of Data Collection

The purpose of the collection of this data was to

  • Find out the factors that influence the risk of heart diseases

  • Explore the relationship between various risk factors

1.3 Data Collection Process

The dataset was sourced from Kaggle, specifically from the Heart Disease dataset provided by Oktay Rdeki. It compiles health records and survey data from various patients, detailing risk factors and their association with heart disease. The dataset was collected from medical records and health surveys from 10,000 patients over a period of five years in multiple hospitals across the United States. It includes self-reported behaviors (e.g., smoking, alcohol consumption) and medically recorded variables (e.g., cholesterol level, blood pressure). It consist of 9 numerical and 12 categorical variables.

2 Data Exploration

data<- read.csv("https://raw.githubusercontent.com/Christina-tinaa/Heart-Disease/main/heart_disease.csv")

library(tidyverse)

str(data)
'data.frame':   10000 obs. of  21 variables:
 $ Age                 : num  56 69 46 32 60 25 78 38 56 75 ...
 $ Gender              : chr  "Male" "Female" "Male" "Female" ...
 $ Blood.Pressure      : num  153 146 126 122 166 152 121 161 135 144 ...
 $ Cholesterol.Level   : num  155 286 216 293 242 257 175 187 291 252 ...
 $ Exercise.Habits     : chr  "High" "High" "Low" "High" ...
 $ Smoking             : chr  "Yes" "No" "No" "Yes" ...
 $ Family.Heart.Disease: chr  "Yes" "Yes" "No" "Yes" ...
 $ Diabetes            : chr  "No" "Yes" "No" "No" ...
 $ BMI                 : num  25 25.2 29.9 24.1 20.5 ...
 $ High.Blood.Pressure : chr  "Yes" "No" "No" "Yes" ...
 $ Low.HDL.Cholesterol : chr  "Yes" "Yes" "Yes" "No" ...
 $ High.LDL.Cholesterol: chr  "No" "No" "Yes" "Yes" ...
 $ Alcohol.Consumption : chr  "High" "Medium" "Low" "Low" ...
 $ Stress.Level        : chr  "Medium" "High" "Low" "High" ...
 $ Sleep.Hours         : num  7.63 8.74 4.44 5.25 7.03 ...
 $ Sugar.Consumption   : chr  "Medium" "Medium" "Low" "High" ...
 $ Triglyceride.Level  : num  342 133 393 293 263 126 107 228 317 199 ...
 $ Fasting.Blood.Sugar : num  NA 157 92 94 154 91 85 111 103 96 ...
 $ CRP.Level           : num  12.97 9.36 12.71 12.51 10.38 ...
 $ Homocysteine.Level  : num  12.39 19.3 11.23 5.96 8.15 ...
 $ Heart.Disease.Status: chr  "No" "No" "No" "No" ...
summary(data)
      Age          Gender          Blood.Pressure  Cholesterol.Level
 Min.   :18.0   Length:10000       Min.   :120.0   Min.   :150.0    
 1st Qu.:34.0   Class :character   1st Qu.:134.0   1st Qu.:187.0    
 Median :49.0   Mode  :character   Median :150.0   Median :226.0    
 Mean   :49.3                      Mean   :149.8   Mean   :225.4    
 3rd Qu.:65.0                      3rd Qu.:165.0   3rd Qu.:263.0    
 Max.   :80.0                      Max.   :180.0   Max.   :300.0    
 NA's   :29                        NA's   :19      NA's   :30       
 Exercise.Habits      Smoking          Family.Heart.Disease   Diabetes        
 Length:10000       Length:10000       Length:10000         Length:10000      
 Class :character   Class :character   Class :character     Class :character  
 Mode  :character   Mode  :character   Mode  :character     Mode  :character  
                                                                              
                                                                              
                                                                              
                                                                              
      BMI        High.Blood.Pressure Low.HDL.Cholesterol High.LDL.Cholesterol
 Min.   :18.00   Length:10000        Length:10000        Length:10000        
 1st Qu.:23.66   Class :character    Class :character    Class :character    
 Median :29.08   Mode  :character    Mode  :character    Mode  :character    
 Mean   :29.08                                                               
 3rd Qu.:34.52                                                               
 Max.   :40.00                                                               
 NA's   :22                                                                  
 Alcohol.Consumption Stress.Level        Sleep.Hours     Sugar.Consumption 
 Length:10000        Length:10000       Min.   : 4.001   Length:10000      
 Class :character    Class :character   1st Qu.: 5.450   Class :character  
 Mode  :character    Mode  :character   Median : 7.003   Mode  :character  
                                        Mean   : 6.991                     
                                        3rd Qu.: 8.532                     
                                        Max.   :10.000                     
                                        NA's   :25                         
 Triglyceride.Level Fasting.Blood.Sugar   CRP.Level         Homocysteine.Level
 Min.   :100.0      Min.   : 80.0       Min.   : 0.003647   Min.   : 5.000    
 1st Qu.:176.0      1st Qu.: 99.0       1st Qu.: 3.674126   1st Qu.: 8.723    
 Median :250.0      Median :120.0       Median : 7.472164   Median :12.409    
 Mean   :250.7      Mean   :120.1       Mean   : 7.472201   Mean   :12.456    
 3rd Qu.:326.0      3rd Qu.:141.0       3rd Qu.:11.255592   3rd Qu.:16.141    
 Max.   :400.0      Max.   :160.0       Max.   :14.997087   Max.   :19.999    
 NA's   :26         NA's   :22          NA's   :26          NA's   :20        
 Heart.Disease.Status
 Length:10000        
 Class :character    
 Mode  :character    
                     
                     
                     
                     

2.1 Itemized List of Feature Variables

# Define the feature variables with their descriptions and data types
features <- data.frame(
  Feature_Name = c("Age", "Gender", "Blood Pressure", "Cholesterol Level", "Exercise Habits",
                   "Smoking", "Family Heart Disease", "Diabetes", "BMI", "High Blood Pressure",
                   "Low HDL Cholesterol", "High LDL Cholesterol", "Alcohol Consumption",
                   "Stress Level", "Sleep Hours", "Sugar Consumption", "Triglyceride Level",
                   "Fasting Blood Sugar", "CRP Level", "Homocysteine Level", "Heart Disease Status"),
  
  Description = c("The individual's age", "The individual's gender (Male or Female)",
                  "The individual's blood pressure (systolic)", "The individual's total cholesterol level",
                  "The individual's exercise habits (Low, Medium, High)", "Whether the individual smokes or not (Yes or No)",
                  "Whether there is a family history of heart disease (Yes or No)", "Whether the individual has diabetes (Yes or No)",
                  "The individual's body mass index", "Whether the individual has high blood pressure (Yes or No)",
                  "Whether the individual has low HDL cholesterol (Yes or No)", "Whether the individual has high LDL cholesterol (Yes or No)",
                  "The individual's alcohol consumption level (None, Low, Medium, High)",
                  "The individual's stress level (Low, Medium, High)", "The number of hours the individual sleeps",
                  "The individual's sugar consumption level (Low, Medium, High)", "The individual's triglyceride level",
                  "The individual's fasting blood sugar level", "The C-reactive protein level (a marker of inflammation)",
                  "The individual's homocysteine level (an amino acid that affects blood vessel health)",
                  "The individual's heart disease status (Yes or No)"),
  
  Data_Type = c("Numerical", "Categorical", "Numerical", "Numerical", "Categorical",
                "Categorical", "Categorical", "Categorical", "Numerical", "Categorical",
                "Categorical", "Categorical", "Categorical",
                "Categorical", "Numerical", "Categorical", "Numerical",
                "Numerical", "Numerical", "Numerical", "Categorical")
)

# Print the table
kable(features)
Feature_Name Description Data_Type
Age The individual’s age Numerical
Gender The individual’s gender (Male or Female) Categorical
Blood Pressure The individual’s blood pressure (systolic) Numerical
Cholesterol Level The individual’s total cholesterol level Numerical
Exercise Habits The individual’s exercise habits (Low, Medium, High) Categorical
Smoking Whether the individual smokes or not (Yes or No) Categorical
Family Heart Disease Whether there is a family history of heart disease (Yes or No) Categorical
Diabetes Whether the individual has diabetes (Yes or No) Categorical
BMI The individual’s body mass index Numerical
High Blood Pressure Whether the individual has high blood pressure (Yes or No) Categorical
Low HDL Cholesterol Whether the individual has low HDL cholesterol (Yes or No) Categorical
High LDL Cholesterol Whether the individual has high LDL cholesterol (Yes or No) Categorical
Alcohol Consumption The individual’s alcohol consumption level (None, Low, Medium, High) Categorical
Stress Level The individual’s stress level (Low, Medium, High) Categorical
Sleep Hours The number of hours the individual sleeps Numerical
Sugar Consumption The individual’s sugar consumption level (Low, Medium, High) Categorical
Triglyceride Level The individual’s triglyceride level Numerical
Fasting Blood Sugar The individual’s fasting blood sugar level Numerical
CRP Level The C-reactive protein level (a marker of inflammation) Numerical
Homocysteine Level The individual’s homocysteine level (an amino acid that affects blood vessel health) Numerical
Heart Disease Status The individual’s heart disease status (Yes or No) Categorical

2.2 Purposes of Using This Data Set

This dataset will be used to:

  1. Identify significant risk factors associated with heart disease.

  2. Examine interactions between lifestyle, biochemical markers, and cardiovascular health.

  3. Develop predictive models for heart disease risk assessment.

2.3 Problem Statements

  • What are the primary predictors of heart disease?
  • How do lifestyle factors (e.g., smoking, exercise, alcohol consumption) impact heart disease risk?
  • What is the relationship between cholesterol levels and other biochemical markers?

3 Distribution of Individual Features

Several features have missing values, particularly in health-related metrics.Missing data can impact modeling accuracy and must be addressed via imputation techniques.

Preparing for analysis requires the following tasks:

  1. Handling Missing Values
  2. Addressing Outliers

3.1 Handling Missing Values

heart_disease has missing values for some variables, these missing values are as follows Age, cholestrol level, blood pressure, BMI, Sleep hours, cholestrol level, Triglyceride.Level, Fasting.Blood.Sugar, CRP Level, and Homocysteine.Level. To handle observations with missing data, imputation will be performed prior to analysis.

# PLOTTING MISSING VALUES

# Generating data frame of missing values per variable
MissingVal <- data.frame(
  Variables = names(data),
  Missing = colSums(is.na(data))
)

# Generating interactive plot using plotly
Plot_MissingVal <- 
  # Taking a subset of MissingVal, so only entries with > 0 missing values will be displayed
  subset(MissingVal, Missing > 0) %>% 
  # Passing the subset to plot_ly
  plot_ly(
    x = ~Variables,
    y = ~Missing
  ) %>% 
  layout(
    title = list(
      text = "Missing Values per Variable"
    ),
    xaxis = list(
      title = "Variables with Missing Values",
      categoryorder = "trace"
    ),
    yaxis = list(
      title = "Number of Missing Values"
    )
  )

# Outputting plot
Plot_MissingVal

3.2 Addressing Outliers

Of particular note is the wide variability in Triglyceride Level and Fasting Blood Sugar. Typical triglyceride levels are classified as follows: normal (<150 mg/dL), borderline high (150–199 mg/dL), high (200–499 mg/dL), and very high (>500 mg/dL). For fasting blood sugar, normal levels range between 70–100 mg/dL, while levels above 125 mg/dL are indicative of diabetes.

However, there are some Triglyceride Level values exceeding 400 mg/dL and Fasting Blood Sugar values exceeding 300 mg/dL. Such extreme values may reflect individuals with severe underlying conditions (e.g., hypertriglyceridemia or poorly managed diabetes). If these values do not align with medical plausibility or diagnostic thresholds, they could also represent measurement errors or data entry issues.

# ====================
# PLOTTING ALL NUMERICAL NON-BINARY VARIABLES
# ====================

# Selecting only numeric variables
Numeric_Var <- select(data, where(is.numeric))

# Eliminating any binary variables
Numeric_Var <- Numeric_Var[!apply(Numeric_Var, 2, function(x){all(match(x, c(0, 1, NA), nomatch = FALSE))})]

# Preparing a list of subplots
Numeric_Fig <- c()
# Using a for loop to generate a subplot per variable in Numeric_Var
for(i in 1:length(names(Numeric_Var))){
  Numeric_Fig[[i]] <- plot_ly(
    x = Numeric_Var[[i]], 
    y = "", 
    type = "box",
    name = colnames(Numeric_Var)[i]
  )
}

# Generating a plot that contains 8 subplots (one for each variable in Numeric_Var) across 4 rows
Plot_Numeric_Var <- 
  subplot(Numeric_Fig[[1]], Numeric_Fig[[2]], Numeric_Fig[[3]], Numeric_Fig[[4]], Numeric_Fig[[5]], Numeric_Fig[[6]], Numeric_Fig[[7]], Numeric_Fig[[8]], nrows = 4, margin = 0.05) %>% 
  layout(
    title = "Distributions of All Numerical Non-binary Variables",
    legend = list(
      title = list(text = "<b> Variable </b>"),
      bgcolor = "yellow",
      bordercolor = "orange",
      borderwidth = 2
    )
  )

# Outputting plot
Plot_Numeric_Var

4 Relationship Between Features

4.1 Cholesterol Level and Triglyceride Level

There appears to be no strong visible linear trend between cholesterol and triglyceride levels. Both variables have a wide distribution across all values.

# Generating plot
CT <- 
  plot_ly(
    data = data,
    x = ~Cholesterol.Level,
    y = ~Triglyceride.Level
  ) %>% 
  layout(
    title = "Cholesterol Level and Triglyceride Level",
    xaxis = list(title = "Cholesterol Level"),
    yaxis = list(title = "Triglyceride Level")
  )

# Outputting plot
CT

4.2 Gender and Exercise Habits

Both males and females show similar patterns in exercise habits, with the highest count in “high exercise” and similar distributions across “medium” and “low” categories.

# Preparing plot data
Gender_Exercise <- 
  data %>%
  group_by(Gender, Exercise.Habits) %>%
  summarise(Count = n())

# Generating plot
GE <- plot_ly()
GE <- GE %>% 
  add_trace(
    data = subset(Gender_Exercise, Exercise.Habits == "Low"),
    x = ~Gender,
    y = ~Count,
    name = "Low"
  ) %>% 
  add_trace(
    data = subset(Gender_Exercise, Exercise.Habits == "Medium"),
    x = ~Gender,
    y = ~Count,
    name = "Medium"
  ) %>%
  add_trace(
    data = subset(Gender_Exercise, Exercise.Habits == "High"),
    x = ~Gender,
    y = ~Count,
    name = "High"
  ) %>% 
  layout(
    title = "Gender and Exercise Habits",
    xaxis = list(title = "Gender"),
    yaxis = list(title = "Count"),
    legend = list(
      title = list(text = "<b> Exercise Habits </b>"),
      bgcolor = "#E2E2E2",
      bordercolor = "#FFFFFF",
      borderwidth = 2
    )
  )

# Outputting plot
GE

4.3 Alcohol Consumption and Heart Disease Status

Most individuals who consume alcohol at low, medium, or no levels do not have heart disease. However, the number of individuals with heart disease is consistent across these categories.

# Preparing plot data
Alcohol_HeartDisease <- 
  data %>%
  group_by(Alcohol.Consumption, Heart.Disease.Status) %>%
  summarise(Count = n())

# Generating plot
AH <- plot_ly() %>% 
  add_trace(
    data = Alcohol_HeartDisease,
    x = ~Alcohol.Consumption, 
    y = ~Count, 
    type = "bar",
    color = ~Heart.Disease.Status
  ) %>% 
  layout(
    title = "Alcohol Consumption and Heart Disease Status",
    xaxis = list(title = "Alcohol Consumption"),
    yaxis = list(title = "Count"),
    legend = list(
      title = list(text = "<b> Heart Disease Status </b>"),
      bgcolor = "#E2E2E2",
      bordercolor = "#FFFFFF",
      borderwidth = 2
    )
  )

# Outputting plot
AH

4.4 Cholesterol Level, Triglyceride Level, and BMI

The 3D scatterplot shows no clear clustering or pattern among these three variables. BMI, cholesterol, and triglycerides are spread widely across all ranges.

# Generating plot
CTB <- plot_ly() %>% 
  add_trace(
    data = data,
    x = ~Cholesterol.Level, 
    y = ~Triglyceride.Level, 
    z = ~BMI,
    marker = list(size = 2),
    hovertemplate = paste(
      "<b>Cholesterol Level</b>: %{x}<br>",
      "<b>Triglyceride Level</b>: %{y}<br>",
      "<b>BMI</b>: %{z}"
    ),
    name = ""
  ) %>%
  layout(
    title = "Cholesterol Level, Triglyceride Level, and BMI",
    scene = list(
      xaxis = list(title = "Cholesterol Level"),
      yaxis = list(title = "Triglyceride Level"),
      zaxis = list(title = "BMI"),
      aspectmode = "cube"
    )
  )

# Outputting plot
CTB
LS0tDQp0aXRsZTogIkhFQVJUIERJU0VBU0UgUklTSyBBTkFMWVNJUyINCmF1dGhvcjogIkNIUklTVElOQSBUSE9NUFNPTiBBQ1FVQUgiDQpkYXRlOiAiICINCm91dHB1dDoNCiAgaHRtbF9kb2N1bWVudDogDQogICAgdG9jOiB5ZXMNCiAgICB0b2NfZGVwdGg6IDQNCiAgICB0b2NfZmxvYXQ6IHllcw0KICAgIG51bWJlcl9zZWN0aW9uczogeWVzDQogICAgdG9jX2NvbGxhcHNlZDogeWVzDQogICAgY29kZV9mb2xkaW5nOiBoaWRlDQogICAgY29kZV9kb3dubG9hZDogeWVzDQogICAgc21vb3RoX3Njcm9sbDogeWVzDQogICAgdGhlbWU6IGx1bWVuDQogIHdvcmRfZG9jdW1lbnQ6IA0KICAgIHRvYzogeWVzDQogICAgdG9jX2RlcHRoOiA0DQogICAgZmlnX2NhcHRpb246IHllcw0KICAgIGtlZXBfbWQ6IHllcw0KICBwZGZfZG9jdW1lbnQ6IA0KICAgIHRvYzogeWVzDQogICAgdG9jX2RlcHRoOiA0DQogICAgZmlnX2NhcHRpb246IHllcw0KICAgIG51bWJlcl9zZWN0aW9uczogbm8NCiAgICBmaWdfd2lkdGg6IDMNCiAgICBmaWdfaGVpZ2h0OiAzDQplZGl0b3Jfb3B0aW9uczogDQogIGNodW5rX291dHB1dF90eXBlOiBpbmxpbmUNCi0tLQ0KDQpgYGB7PWh0bWx9DQoNCjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+DQoNCi8qIENhc2NhZGluZyBTdHlsZSBTaGVldHMgKENTUykgaXMgYSBzdHlsZXNoZWV0IGxhbmd1YWdlIHVzZWQgdG8gZGVzY3JpYmUgdGhlIHByZXNlbnRhdGlvbiBvZiBhIGRvY3VtZW50IHdyaXR0ZW4gaW4gSFRNTCBvciBYTUwuIGl0IGlzIGEgc2ltcGxlIG1lY2hhbmlzbSBmb3IgYWRkaW5nIHN0eWxlIChlLmcuLCBmb250cywgY29sb3JzLCBzcGFjaW5nKSB0byBXZWIgZG9jdW1lbnRzLiAqLw0KDQpoMS50aXRsZSB7ICAvKiBUaXRsZSAtIGZvbnQgc3BlY2lmaWNhdGlvbnMgb2YgdGhlIHJlcG9ydCB0aXRsZSAqLw0KICBmb250LXNpemU6IDIycHg7DQogIGZvbnQtd2VpZ2h0OiBib2xkOw0KICBjb2xvcjogRGFya1JlZDsNCiAgdGV4dC1hbGlnbjogY2VudGVyOw0KICBmb250LWZhbWlseTogIkdpbGwgU2FucyIsIHNhbnMtc2VyaWY7DQp9DQpoNC5hdXRob3IgeyAvKiBIZWFkZXIgNCAtIGZvbnQgc3BlY2lmaWNhdGlvbnMgZm9yIGF1dGhvcnMgICovDQogIGZvbnQtc2l6ZTogMThweDsNCiAgZm9udC13ZWlnaHQ6IGJvbGQ7DQogIGZvbnQtZmFtaWx5OiBzeXN0ZW0tdWk7DQogIGNvbG9yOiBuYXZ5Ow0KICB0ZXh0LWFsaWduOiBjZW50ZXI7DQp9DQpoNC5kYXRlIHsgLyogSGVhZGVyIDQgLSBmb250IHNwZWNpZmljYXRpb25zIGZvciB0aGUgZGF0ZSAgKi8NCiAgZm9udC1zaXplOiAxOHB4Ow0KICBmb250LWZhbWlseTogc3lzdGVtLXVpOw0KICBjb2xvcjogRGFya0JsdWU7DQogIHRleHQtYWxpZ246IGNlbnRlcjsNCiAgZm9udC13ZWlnaHQ6IGJvbGQ7DQp9DQpoMSB7IC8qIEhlYWRlciAxIC0gZm9udCBzcGVjaWZpY2F0aW9ucyBmb3IgbGV2ZWwgMSBzZWN0aW9uIHRpdGxlICAqLw0KICAgIGZvbnQtc2l6ZTogMjJweDsNCiAgICBmb250LWZhbWlseTogIlRpbWVzIE5ldyBSb21hbiIsIFRpbWVzLCBzZXJpZjsNCiAgICBjb2xvcjogbmF2eTsNCiAgICB0ZXh0LWFsaWduOiBjZW50ZXI7DQogICAgZm9udC13ZWlnaHQ6IGJvbGQ7DQp9DQpoMiB7IC8qIEhlYWRlciAyIC0gZm9udCBzcGVjaWZpY2F0aW9ucyBmb3IgbGV2ZWwgMiBzZWN0aW9uIHRpdGxlICovDQogICAgZm9udC1zaXplOiAyMHB4Ow0KICAgIGZvbnQtZmFtaWx5OiAiVGltZXMgTmV3IFJvbWFuIiwgVGltZXMsIHNlcmlmOw0KICAgIGNvbG9yOiBuYXZ5Ow0KICAgIHRleHQtYWxpZ246IGxlZnQ7DQogICAgZm9udC13ZWlnaHQ6IGJvbGQ7DQp9DQoNCmgzIHsgLyogSGVhZGVyIDMgLSBmb250IHNwZWNpZmljYXRpb25zIG9mIGxldmVsIDMgc2VjdGlvbiB0aXRsZSAgKi8NCiAgICBmb250LXNpemU6IDE4cHg7DQogICAgZm9udC1mYW1pbHk6ICJUaW1lcyBOZXcgUm9tYW4iLCBUaW1lcywgc2VyaWY7DQogICAgY29sb3I6IG5hdnk7DQogICAgdGV4dC1hbGlnbjogbGVmdDsNCn0NCg0KaDQgeyAvKiBIZWFkZXIgNCAtIGZvbnQgc3BlY2lmaWNhdGlvbnMgb2YgbGV2ZWwgNCBzZWN0aW9uIHRpdGxlICAqLw0KICAgIGZvbnQtc2l6ZTogMThweDsNCiAgICBmb250LWZhbWlseTogIlRpbWVzIE5ldyBSb21hbiIsIFRpbWVzLCBzZXJpZjsNCiAgICBjb2xvcjogZGFya3JlZDsNCiAgICB0ZXh0LWFsaWduOiBsZWZ0Ow0KfQ0KDQpib2R5IHsgYmFja2dyb3VuZC1jb2xvcjp3aGl0ZTsgfQ0KDQouaGlnaGxpZ2h0bWUgeyBiYWNrZ3JvdW5kLWNvbG9yOnllbGxvdzsgfQ0KDQpwIHsgYmFja2dyb3VuZC1jb2xvcjp3aGl0ZTsgfQ0KDQo8L3N0eWxlPg0KYGBgDQoNCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQ0KIyBjb2RlIGNodW5rIHNwZWNpZmllcyB3aGV0aGVyIHRoZSBSIGNvZGUsIHdhcm5pbmdzLCBhbmQgb3V0cHV0IHdpbGwgYmUgaW5jbHVkZWQgaW4gdGhlIG91dHB1dCBmaWxlcy4NCmlmICghcmVxdWlyZSgia25pdHIiKSkgew0KICAgaW5zdGFsbC5wYWNrYWdlcygia25pdHIiKQ0KICAgbGlicmFyeShrbml0cikNCn0NCmlmICghcmVxdWlyZSgidGlkeXZlcnNlIikpIHsNCiAgIGluc3RhbGwucGFja2FnZXMoInRpZHl2ZXJzZSIpDQpsaWJyYXJ5KHRpZHl2ZXJzZSkNCn0NCmlmICghcmVxdWlyZSgicGFsbWVycGVuZ3VpbnMiKSkgew0KICAgaW5zdGFsbC5wYWNrYWdlcygicGFsbWVycGVuZ3VpbnMiKQ0KbGlicmFyeShwYWxtZXJwZW5ndWlucykNCn0NCmlmICghcmVxdWlyZSgicGxvdGx5IikpIHsNCiAgIGluc3RhbGwucGFja2FnZXMoInBsb3RseSIpDQpsaWJyYXJ5KHBsb3RseSkNCn0NCmlmICghcmVxdWlyZSgiR0dhbGx5IikpIHsNCiAgIGluc3RhbGwucGFja2FnZXMoIkdHYWxseSIpDQpsaWJyYXJ5KEdHYWxseSkNCn0NCmlmICghcmVxdWlyZSgibmFuaWFyIikpIHsNCiAgIGluc3RhbGwucGFja2FnZXMoIm5hbmlhciIpDQpsaWJyYXJ5KG5hbmlhcikNCn0NCmlmICghcmVxdWlyZSgicG9vbCIpKSB7DQogICBpbnN0YWxsLnBhY2thZ2VzKCJwb29sIikNCmxpYnJhcnkocG9vbCkNCn0NCmlmICghcmVxdWlyZSgiREJJIikpIHsNCiAgIGluc3RhbGwucGFja2FnZXMoIkRCSSIpDQpsaWJyYXJ5KERCSSkNCn0NCmlmICghcmVxdWlyZSgiUk15U1FMIikpIHsNCiAgIGluc3RhbGwucGFja2FnZXMoIlJNeVNRTCIpDQpsaWJyYXJ5KFJNeVNRTCkNCn0NCmlmICghcmVxdWlyZSgicmFuZG9tRm9yZXN0IikpIHsNCiAgIGluc3RhbGwucGFja2FnZXMoInJhbmRvbUZvcmVzdCIpDQpsaWJyYXJ5KHJhbmRvbUZvcmVzdCkNCn0NCmlmICghcmVxdWlyZSgiZ2dpcmFwaCIpKSB7DQogICBpbnN0YWxsLnBhY2thZ2VzKCJnZ2lyYXBoIikNCmxpYnJhcnkoZ2dpcmFwaCkNCn0NCmlmICghcmVxdWlyZSgiaGlnaGNoYXJ0ZXIiKSkgew0KICAgaW5zdGFsbC5wYWNrYWdlcygiaGlnaGNoYXJ0ZXIiKQ0KbGlicmFyeShoaWdoY2hhcnRlcikNCn0NCmlmICghcmVxdWlyZSgiYnJvb20iKSkgew0KICAgaW5zdGFsbC5wYWNrYWdlcygiYnJvb20iKQ0KbGlicmFyeShicm9vbSkNCn0NCiMjIA0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KA0KICAjIGluY2x1ZGUgY29kZSBjaHVuayBpbiB0aGUgb3V0cHV0IGZpbGUNCiAgZWNobyA9IFRSVUUsDQogICMgc29tZXRpbWVzLCB5b3UgY29kZSBtYXkgcHJvZHVjZSB3YXJuaW5nIG1lc3NhZ2VzLCB5b3UgY2FuIGNob29zZSB0byBpbmNsdWRlIHRoZSB3YXJuaW5nIG1lc3NhZ2VzIGluIHRoZSBvdXRwdXQgZmlsZS4NCiAgd2FybmluZyA9IEZBTFNFLCANCiAgIyB5b3UgY2FuIGFsc28gZGVjaWRlIHdoZXRoZXIgdG8gaW5jbHVkZSB0aGUgb3V0cHV0IGluIHRoZSBvdXRwdXQgZmlsZS4NCiAgcmVzdWx0cyA9IFRSVUUsIA0KICBtZXNzYWdlID0gRkFMU0UsDQogIGNvbW1lbnQgPSBOQQ0KKSAgDQoNCmBgYA0KDQojICoqMS4gSW50cm9kdWN0aW9uKioNCg0KIyMgKipEZXNjcmlwdGlvbiBvZiBEYXRhKioNClRoaXMgZGF0YXNldCB3YXMgb2J0YWluZWQgZnJvbSBbS2FnZ2xlXShodHRwczovL3d3dy5rYWdnbGUuY29tL2RhdGFzZXRzL29rdGF5cmRla2kvaGVhcnQtZGlzZWFzZSkuVGhpcyBkYXRhc2V0IGNvbnRhaW5zIGhlYWx0aCBhbmQgcmlzayBmYWN0b3JzIHJlbGF0ZWQgdG8gdGhlIGhlYXJ0IGRpc2Vhc2UuIFRoZSBkYXRhc2V0IGludm9sdmVzIHBhcmFtZXRlcnMgc3VjaCBhcyBkaWFiZXRlcyxzdHJlc3MgbGV2ZWwsIHNtb2tpbmcsYWdlLGdlbmRlciBhbW9uZyBvdGhlcnMgdG8gYW5hbHlzZSB0aGUgcmlzayBvZiBoZWFydCBkaXNlYXNlIGFuZCBjb250cmlidXRlIGVmZmVjdGl2ZWx5IHRvIGhlYWx0aCByZXNlYXJjaC4gVGhpcyBkYXRhc2V0IGNhbiBiZSB1c2VkIHRvIHN0dWR5IHRoZSBmYWN0b3JzIHRoYXQgY29udHJpYnV0ZSB0byB0aGUgZGV2ZWxvcG1lbnQgb2YgaGVhcnQgZGlzZWFzZXMuDQoNCiMjIFB1cnBvc2Ugb2YgRGF0YSBDb2xsZWN0aW9uDQoNClRoZSBwdXJwb3NlIG9mIHRoZSBjb2xsZWN0aW9uIG9mIHRoaXMgZGF0YSB3YXMgdG8NCg0KLSBGaW5kIG91dCB0aGUgZmFjdG9ycyB0aGF0IGluZmx1ZW5jZSB0aGUgcmlzayBvZiBoZWFydCBkaXNlYXNlcw0KDQotIEV4cGxvcmUgdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIHZhcmlvdXMgcmlzayBmYWN0b3JzDQoNCiMjIERhdGEgQ29sbGVjdGlvbiBQcm9jZXNzDQpUaGUgZGF0YXNldCB3YXMgc291cmNlZCBmcm9tIEthZ2dsZSwgc3BlY2lmaWNhbGx5IGZyb20gdGhlIEhlYXJ0IERpc2Vhc2UgZGF0YXNldCBwcm92aWRlZCBieSBPa3RheSBSZGVraS4gSXQgY29tcGlsZXMgaGVhbHRoIHJlY29yZHMgYW5kIHN1cnZleSBkYXRhIGZyb20gdmFyaW91cyBwYXRpZW50cywgZGV0YWlsaW5nIHJpc2sgZmFjdG9ycyBhbmQgdGhlaXIgYXNzb2NpYXRpb24gd2l0aCBoZWFydCBkaXNlYXNlLg0KVGhlIGRhdGFzZXQgd2FzIGNvbGxlY3RlZCBmcm9tIG1lZGljYWwgcmVjb3JkcyBhbmQgaGVhbHRoIHN1cnZleXMgZnJvbSAxMCwwMDAgcGF0aWVudHMgb3ZlciBhIHBlcmlvZCBvZiBmaXZlIHllYXJzIGluIG11bHRpcGxlIGhvc3BpdGFscyBhY3Jvc3MgdGhlIFVuaXRlZCBTdGF0ZXMuIEl0IGluY2x1ZGVzIHNlbGYtcmVwb3J0ZWQgYmVoYXZpb3JzIChlLmcuLCBzbW9raW5nLCBhbGNvaG9sIGNvbnN1bXB0aW9uKSBhbmQgbWVkaWNhbGx5IHJlY29yZGVkIHZhcmlhYmxlcyAoZS5nLiwgY2hvbGVzdGVyb2wgbGV2ZWwsIGJsb29kIHByZXNzdXJlKS4gSXQgY29uc2lzdCBvZiA5IG51bWVyaWNhbCBhbmQgMTIgY2F0ZWdvcmljYWwgdmFyaWFibGVzLg0KDQojIERhdGEgRXhwbG9yYXRpb24NCg0KYGBge3J9DQoNCmRhdGE8LSByZWFkLmNzdigiaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL0NocmlzdGluYS10aW5hYS9IZWFydC1EaXNlYXNlL21haW4vaGVhcnRfZGlzZWFzZS5jc3YiKQ0KDQpsaWJyYXJ5KHRpZHl2ZXJzZSkNCg0Kc3RyKGRhdGEpDQpzdW1tYXJ5KGRhdGEpDQoNCmBgYA0KDQojIyAqSXRlbWl6ZWQgTGlzdCBvZiBGZWF0dXJlIFZhcmlhYmxlcyoNCmBgYHtyIH0NCg0KIyBEZWZpbmUgdGhlIGZlYXR1cmUgdmFyaWFibGVzIHdpdGggdGhlaXIgZGVzY3JpcHRpb25zIGFuZCBkYXRhIHR5cGVzDQpmZWF0dXJlcyA8LSBkYXRhLmZyYW1lKA0KICBGZWF0dXJlX05hbWUgPSBjKCJBZ2UiLCAiR2VuZGVyIiwgIkJsb29kIFByZXNzdXJlIiwgIkNob2xlc3Rlcm9sIExldmVsIiwgIkV4ZXJjaXNlIEhhYml0cyIsDQogICAgICAgICAgICAgICAgICAgIlNtb2tpbmciLCAiRmFtaWx5IEhlYXJ0IERpc2Vhc2UiLCAiRGlhYmV0ZXMiLCAiQk1JIiwgIkhpZ2ggQmxvb2QgUHJlc3N1cmUiLA0KICAgICAgICAgICAgICAgICAgICJMb3cgSERMIENob2xlc3Rlcm9sIiwgIkhpZ2ggTERMIENob2xlc3Rlcm9sIiwgIkFsY29ob2wgQ29uc3VtcHRpb24iLA0KICAgICAgICAgICAgICAgICAgICJTdHJlc3MgTGV2ZWwiLCAiU2xlZXAgSG91cnMiLCAiU3VnYXIgQ29uc3VtcHRpb24iLCAiVHJpZ2x5Y2VyaWRlIExldmVsIiwNCiAgICAgICAgICAgICAgICAgICAiRmFzdGluZyBCbG9vZCBTdWdhciIsICJDUlAgTGV2ZWwiLCAiSG9tb2N5c3RlaW5lIExldmVsIiwgIkhlYXJ0IERpc2Vhc2UgU3RhdHVzIiksDQogIA0KICBEZXNjcmlwdGlvbiA9IGMoIlRoZSBpbmRpdmlkdWFsJ3MgYWdlIiwgIlRoZSBpbmRpdmlkdWFsJ3MgZ2VuZGVyIChNYWxlIG9yIEZlbWFsZSkiLA0KICAgICAgICAgICAgICAgICAgIlRoZSBpbmRpdmlkdWFsJ3MgYmxvb2QgcHJlc3N1cmUgKHN5c3RvbGljKSIsICJUaGUgaW5kaXZpZHVhbCdzIHRvdGFsIGNob2xlc3Rlcm9sIGxldmVsIiwNCiAgICAgICAgICAgICAgICAgICJUaGUgaW5kaXZpZHVhbCdzIGV4ZXJjaXNlIGhhYml0cyAoTG93LCBNZWRpdW0sIEhpZ2gpIiwgIldoZXRoZXIgdGhlIGluZGl2aWR1YWwgc21va2VzIG9yIG5vdCAoWWVzIG9yIE5vKSIsDQogICAgICAgICAgICAgICAgICAiV2hldGhlciB0aGVyZSBpcyBhIGZhbWlseSBoaXN0b3J5IG9mIGhlYXJ0IGRpc2Vhc2UgKFllcyBvciBObykiLCAiV2hldGhlciB0aGUgaW5kaXZpZHVhbCBoYXMgZGlhYmV0ZXMgKFllcyBvciBObykiLA0KICAgICAgICAgICAgICAgICAgIlRoZSBpbmRpdmlkdWFsJ3MgYm9keSBtYXNzIGluZGV4IiwgIldoZXRoZXIgdGhlIGluZGl2aWR1YWwgaGFzIGhpZ2ggYmxvb2QgcHJlc3N1cmUgKFllcyBvciBObykiLA0KICAgICAgICAgICAgICAgICAgIldoZXRoZXIgdGhlIGluZGl2aWR1YWwgaGFzIGxvdyBIREwgY2hvbGVzdGVyb2wgKFllcyBvciBObykiLCAiV2hldGhlciB0aGUgaW5kaXZpZHVhbCBoYXMgaGlnaCBMREwgY2hvbGVzdGVyb2wgKFllcyBvciBObykiLA0KICAgICAgICAgICAgICAgICAgIlRoZSBpbmRpdmlkdWFsJ3MgYWxjb2hvbCBjb25zdW1wdGlvbiBsZXZlbCAoTm9uZSwgTG93LCBNZWRpdW0sIEhpZ2gpIiwNCiAgICAgICAgICAgICAgICAgICJUaGUgaW5kaXZpZHVhbCdzIHN0cmVzcyBsZXZlbCAoTG93LCBNZWRpdW0sIEhpZ2gpIiwgIlRoZSBudW1iZXIgb2YgaG91cnMgdGhlIGluZGl2aWR1YWwgc2xlZXBzIiwNCiAgICAgICAgICAgICAgICAgICJUaGUgaW5kaXZpZHVhbCdzIHN1Z2FyIGNvbnN1bXB0aW9uIGxldmVsIChMb3csIE1lZGl1bSwgSGlnaCkiLCAiVGhlIGluZGl2aWR1YWwncyB0cmlnbHljZXJpZGUgbGV2ZWwiLA0KICAgICAgICAgICAgICAgICAgIlRoZSBpbmRpdmlkdWFsJ3MgZmFzdGluZyBibG9vZCBzdWdhciBsZXZlbCIsICJUaGUgQy1yZWFjdGl2ZSBwcm90ZWluIGxldmVsIChhIG1hcmtlciBvZiBpbmZsYW1tYXRpb24pIiwNCiAgICAgICAgICAgICAgICAgICJUaGUgaW5kaXZpZHVhbCdzIGhvbW9jeXN0ZWluZSBsZXZlbCAoYW4gYW1pbm8gYWNpZCB0aGF0IGFmZmVjdHMgYmxvb2QgdmVzc2VsIGhlYWx0aCkiLA0KICAgICAgICAgICAgICAgICAgIlRoZSBpbmRpdmlkdWFsJ3MgaGVhcnQgZGlzZWFzZSBzdGF0dXMgKFllcyBvciBObykiKSwNCiAgDQogIERhdGFfVHlwZSA9IGMoIk51bWVyaWNhbCIsICJDYXRlZ29yaWNhbCIsICJOdW1lcmljYWwiLCAiTnVtZXJpY2FsIiwgIkNhdGVnb3JpY2FsIiwNCiAgICAgICAgICAgICAgICAiQ2F0ZWdvcmljYWwiLCAiQ2F0ZWdvcmljYWwiLCAiQ2F0ZWdvcmljYWwiLCAiTnVtZXJpY2FsIiwgIkNhdGVnb3JpY2FsIiwNCiAgICAgICAgICAgICAgICAiQ2F0ZWdvcmljYWwiLCAiQ2F0ZWdvcmljYWwiLCAiQ2F0ZWdvcmljYWwiLA0KICAgICAgICAgICAgICAgICJDYXRlZ29yaWNhbCIsICJOdW1lcmljYWwiLCAiQ2F0ZWdvcmljYWwiLCAiTnVtZXJpY2FsIiwNCiAgICAgICAgICAgICAgICAiTnVtZXJpY2FsIiwgIk51bWVyaWNhbCIsICJOdW1lcmljYWwiLCAiQ2F0ZWdvcmljYWwiKQ0KKQ0KDQojIFByaW50IHRoZSB0YWJsZQ0Ka2FibGUoZmVhdHVyZXMpDQpgYGANCg0KIyMgUHVycG9zZXMgb2YgVXNpbmcgVGhpcyBEYXRhIFNldA0KVGhpcyBkYXRhc2V0IHdpbGwgYmUgdXNlZCB0bzoNCg0KMS4gSWRlbnRpZnkgc2lnbmlmaWNhbnQgcmlzayBmYWN0b3JzIGFzc29jaWF0ZWQgd2l0aCBoZWFydCBkaXNlYXNlLg0KDQoyLiBFeGFtaW5lIGludGVyYWN0aW9ucyBiZXR3ZWVuIGxpZmVzdHlsZSwgYmlvY2hlbWljYWwgbWFya2VycywgYW5kIGNhcmRpb3Zhc2N1bGFyIGhlYWx0aC4NCg0KMy4gRGV2ZWxvcCBwcmVkaWN0aXZlIG1vZGVscyBmb3IgaGVhcnQgZGlzZWFzZSByaXNrIGFzc2Vzc21lbnQuDQoNCiMjIFByb2JsZW0gU3RhdGVtZW50cw0KLSBXaGF0IGFyZSB0aGUgcHJpbWFyeSBwcmVkaWN0b3JzIG9mIGhlYXJ0IGRpc2Vhc2U/DQotIEhvdyBkbyBsaWZlc3R5bGUgZmFjdG9ycyAoZS5nLiwgc21va2luZywgZXhlcmNpc2UsIGFsY29ob2wgY29uc3VtcHRpb24pIGltcGFjdCBoZWFydCBkaXNlYXNlIHJpc2s/DQotIFdoYXQgaXMgdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIGNob2xlc3Rlcm9sIGxldmVscyBhbmQgb3RoZXIgYmlvY2hlbWljYWwgbWFya2Vycz8NCg0KDQojIERpc3RyaWJ1dGlvbiBvZiBJbmRpdmlkdWFsIEZlYXR1cmVzDQoNClNldmVyYWwgZmVhdHVyZXMgaGF2ZSBtaXNzaW5nIHZhbHVlcywgcGFydGljdWxhcmx5IGluIGhlYWx0aC1yZWxhdGVkIG1ldHJpY3MuTWlzc2luZyBkYXRhIGNhbiBpbXBhY3QgbW9kZWxpbmcgYWNjdXJhY3kgYW5kIG11c3QgYmUgYWRkcmVzc2VkIHZpYSBpbXB1dGF0aW9uIHRlY2huaXF1ZXMuDQoNCg0KUHJlcGFyaW5nIGZvciBhbmFseXNpcyByZXF1aXJlcyB0aGUgZm9sbG93aW5nIHRhc2tzOg0KDQoxLiBIYW5kbGluZyBNaXNzaW5nIFZhbHVlcw0KMi4gQWRkcmVzc2luZyBPdXRsaWVycw0KDQojIyBIYW5kbGluZyBNaXNzaW5nIFZhbHVlcw0KDQpgaGVhcnRfZGlzZWFzZWAgaGFzIG1pc3NpbmcgdmFsdWVzIGZvciBzb21lIHZhcmlhYmxlcywgdGhlc2UgbWlzc2luZyB2YWx1ZXMgYXJlIGFzIGZvbGxvd3MgYEFnZWAsIGBjaG9sZXN0cm9sIGxldmVsYCwgYGJsb29kIHByZXNzdXJlYCwgYEJNSWAsIGBTbGVlcCBob3Vyc2AsIGBjaG9sZXN0cm9sIGxldmVsYCwgYFRyaWdseWNlcmlkZS5MZXZlbGAsIGBGYXN0aW5nLkJsb29kLlN1Z2FyYCwgYENSUCBMZXZlbGAsIGFuZCBgSG9tb2N5c3RlaW5lLkxldmVsYC4gVG8gaGFuZGxlIG9ic2VydmF0aW9ucyB3aXRoIG1pc3NpbmcgZGF0YSwgaW1wdXRhdGlvbiB3aWxsIGJlIHBlcmZvcm1lZCBwcmlvciB0byBhbmFseXNpcy4NCg0KDQpgYGB7cn0NCiMgUExPVFRJTkcgTUlTU0lORyBWQUxVRVMNCg0KIyBHZW5lcmF0aW5nIGRhdGEgZnJhbWUgb2YgbWlzc2luZyB2YWx1ZXMgcGVyIHZhcmlhYmxlDQpNaXNzaW5nVmFsIDwtIGRhdGEuZnJhbWUoDQogIFZhcmlhYmxlcyA9IG5hbWVzKGRhdGEpLA0KICBNaXNzaW5nID0gY29sU3Vtcyhpcy5uYShkYXRhKSkNCikNCg0KIyBHZW5lcmF0aW5nIGludGVyYWN0aXZlIHBsb3QgdXNpbmcgcGxvdGx5DQpQbG90X01pc3NpbmdWYWwgPC0gDQogICMgVGFraW5nIGEgc3Vic2V0IG9mIE1pc3NpbmdWYWwsIHNvIG9ubHkgZW50cmllcyB3aXRoID4gMCBtaXNzaW5nIHZhbHVlcyB3aWxsIGJlIGRpc3BsYXllZA0KICBzdWJzZXQoTWlzc2luZ1ZhbCwgTWlzc2luZyA+IDApICU+JSANCiAgIyBQYXNzaW5nIHRoZSBzdWJzZXQgdG8gcGxvdF9seQ0KICBwbG90X2x5KA0KICAgIHggPSB+VmFyaWFibGVzLA0KICAgIHkgPSB+TWlzc2luZw0KICApICU+JSANCiAgbGF5b3V0KA0KICAgIHRpdGxlID0gbGlzdCgNCiAgICAgIHRleHQgPSAiTWlzc2luZyBWYWx1ZXMgcGVyIFZhcmlhYmxlIg0KICAgICksDQogICAgeGF4aXMgPSBsaXN0KA0KICAgICAgdGl0bGUgPSAiVmFyaWFibGVzIHdpdGggTWlzc2luZyBWYWx1ZXMiLA0KICAgICAgY2F0ZWdvcnlvcmRlciA9ICJ0cmFjZSINCiAgICApLA0KICAgIHlheGlzID0gbGlzdCgNCiAgICAgIHRpdGxlID0gIk51bWJlciBvZiBNaXNzaW5nIFZhbHVlcyINCiAgICApDQogICkNCg0KIyBPdXRwdXR0aW5nIHBsb3QNClBsb3RfTWlzc2luZ1ZhbA0KYGBgDQoNCg0KIyMgQWRkcmVzc2luZyBPdXRsaWVycw0KT2YgcGFydGljdWxhciBub3RlIGlzIHRoZSB3aWRlIHZhcmlhYmlsaXR5IGluIFRyaWdseWNlcmlkZSBMZXZlbCBhbmQgRmFzdGluZyBCbG9vZCBTdWdhci4gVHlwaWNhbCB0cmlnbHljZXJpZGUgbGV2ZWxzIGFyZSBjbGFzc2lmaWVkIGFzIGZvbGxvd3M6IG5vcm1hbCAoPDE1MCBtZy9kTCksIGJvcmRlcmxpbmUgaGlnaCAoMTUw4oCTMTk5IG1nL2RMKSwgaGlnaCAoMjAw4oCTNDk5IG1nL2RMKSwgYW5kIHZlcnkgaGlnaCAoPjUwMCBtZy9kTCkuIEZvciBmYXN0aW5nIGJsb29kIHN1Z2FyLCBub3JtYWwgbGV2ZWxzIHJhbmdlIGJldHdlZW4gNzDigJMxMDAgbWcvZEwsIHdoaWxlIGxldmVscyBhYm92ZSAxMjUgbWcvZEwgYXJlIGluZGljYXRpdmUgb2YgZGlhYmV0ZXMuDQoNCkhvd2V2ZXIsIHRoZXJlIGFyZSBzb21lIFRyaWdseWNlcmlkZSBMZXZlbCB2YWx1ZXMgZXhjZWVkaW5nIDQwMCBtZy9kTCBhbmQgRmFzdGluZyBCbG9vZCBTdWdhciB2YWx1ZXMgZXhjZWVkaW5nIDMwMCBtZy9kTC4gU3VjaCBleHRyZW1lIHZhbHVlcyBtYXkgcmVmbGVjdCBpbmRpdmlkdWFscyB3aXRoIHNldmVyZSB1bmRlcmx5aW5nIGNvbmRpdGlvbnMgKGUuZy4sIGh5cGVydHJpZ2x5Y2VyaWRlbWlhIG9yIHBvb3JseSBtYW5hZ2VkIGRpYWJldGVzKS4gSWYgdGhlc2UgdmFsdWVzIGRvIG5vdCBhbGlnbiB3aXRoIG1lZGljYWwgcGxhdXNpYmlsaXR5IG9yIGRpYWdub3N0aWMgdGhyZXNob2xkcywgdGhleSBjb3VsZCBhbHNvIHJlcHJlc2VudCBtZWFzdXJlbWVudCBlcnJvcnMgb3IgZGF0YSBlbnRyeSBpc3N1ZXMuDQoNCmBgYHtyfQ0KIyA9PT09PT09PT09PT09PT09PT09PQ0KIyBQTE9UVElORyBBTEwgTlVNRVJJQ0FMIE5PTi1CSU5BUlkgVkFSSUFCTEVTDQojID09PT09PT09PT09PT09PT09PT09DQoNCiMgU2VsZWN0aW5nIG9ubHkgbnVtZXJpYyB2YXJpYWJsZXMNCk51bWVyaWNfVmFyIDwtIHNlbGVjdChkYXRhLCB3aGVyZShpcy5udW1lcmljKSkNCg0KIyBFbGltaW5hdGluZyBhbnkgYmluYXJ5IHZhcmlhYmxlcw0KTnVtZXJpY19WYXIgPC0gTnVtZXJpY19WYXJbIWFwcGx5KE51bWVyaWNfVmFyLCAyLCBmdW5jdGlvbih4KXthbGwobWF0Y2goeCwgYygwLCAxLCBOQSksIG5vbWF0Y2ggPSBGQUxTRSkpfSldDQoNCiMgUHJlcGFyaW5nIGEgbGlzdCBvZiBzdWJwbG90cw0KTnVtZXJpY19GaWcgPC0gYygpDQojIFVzaW5nIGEgZm9yIGxvb3AgdG8gZ2VuZXJhdGUgYSBzdWJwbG90IHBlciB2YXJpYWJsZSBpbiBOdW1lcmljX1Zhcg0KZm9yKGkgaW4gMTpsZW5ndGgobmFtZXMoTnVtZXJpY19WYXIpKSl7DQogIE51bWVyaWNfRmlnW1tpXV0gPC0gcGxvdF9seSgNCiAgICB4ID0gTnVtZXJpY19WYXJbW2ldXSwgDQogICAgeSA9ICIiLCANCiAgICB0eXBlID0gImJveCIsDQogICAgbmFtZSA9IGNvbG5hbWVzKE51bWVyaWNfVmFyKVtpXQ0KICApDQp9DQoNCiMgR2VuZXJhdGluZyBhIHBsb3QgdGhhdCBjb250YWlucyA4IHN1YnBsb3RzIChvbmUgZm9yIGVhY2ggdmFyaWFibGUgaW4gTnVtZXJpY19WYXIpIGFjcm9zcyA0IHJvd3MNClBsb3RfTnVtZXJpY19WYXIgPC0gDQogIHN1YnBsb3QoTnVtZXJpY19GaWdbWzFdXSwgTnVtZXJpY19GaWdbWzJdXSwgTnVtZXJpY19GaWdbWzNdXSwgTnVtZXJpY19GaWdbWzRdXSwgTnVtZXJpY19GaWdbWzVdXSwgTnVtZXJpY19GaWdbWzZdXSwgTnVtZXJpY19GaWdbWzddXSwgTnVtZXJpY19GaWdbWzhdXSwgbnJvd3MgPSA0LCBtYXJnaW4gPSAwLjA1KSAlPiUgDQogIGxheW91dCgNCiAgICB0aXRsZSA9ICJEaXN0cmlidXRpb25zIG9mIEFsbCBOdW1lcmljYWwgTm9uLWJpbmFyeSBWYXJpYWJsZXMiLA0KICAgIGxlZ2VuZCA9IGxpc3QoDQogICAgICB0aXRsZSA9IGxpc3QodGV4dCA9ICI8Yj4gVmFyaWFibGUgPC9iPiIpLA0KICAgICAgYmdjb2xvciA9ICJ5ZWxsb3ciLA0KICAgICAgYm9yZGVyY29sb3IgPSAib3JhbmdlIiwNCiAgICAgIGJvcmRlcndpZHRoID0gMg0KICAgICkNCiAgKQ0KDQojIE91dHB1dHRpbmcgcGxvdA0KUGxvdF9OdW1lcmljX1Zhcg0KYGBgDQojIFJlbGF0aW9uc2hpcCBCZXR3ZWVuIEZlYXR1cmVzDQoNCiMjIGBDaG9sZXN0ZXJvbCBMZXZlbGAgYW5kIGBUcmlnbHljZXJpZGUgTGV2ZWxgDQoNClRoZXJlIGFwcGVhcnMgdG8gYmUgbm8gc3Ryb25nIHZpc2libGUgbGluZWFyIHRyZW5kIGJldHdlZW4gY2hvbGVzdGVyb2wgYW5kIHRyaWdseWNlcmlkZSBsZXZlbHMuIEJvdGggdmFyaWFibGVzIGhhdmUgYSB3aWRlIGRpc3RyaWJ1dGlvbiBhY3Jvc3MgYWxsIHZhbHVlcy4NCg0KYGBge3J9DQojIEdlbmVyYXRpbmcgcGxvdA0KQ1QgPC0gDQogIHBsb3RfbHkoDQogICAgZGF0YSA9IGRhdGEsDQogICAgeCA9IH5DaG9sZXN0ZXJvbC5MZXZlbCwNCiAgICB5ID0gflRyaWdseWNlcmlkZS5MZXZlbA0KICApICU+JSANCiAgbGF5b3V0KA0KICAgIHRpdGxlID0gIkNob2xlc3Rlcm9sIExldmVsIGFuZCBUcmlnbHljZXJpZGUgTGV2ZWwiLA0KICAgIHhheGlzID0gbGlzdCh0aXRsZSA9ICJDaG9sZXN0ZXJvbCBMZXZlbCIpLA0KICAgIHlheGlzID0gbGlzdCh0aXRsZSA9ICJUcmlnbHljZXJpZGUgTGV2ZWwiKQ0KICApDQoNCiMgT3V0cHV0dGluZyBwbG90DQpDVA0KYGBgDQoNCiMjIGBHZW5kZXJgIGFuZCBgRXhlcmNpc2UgSGFiaXRzYA0KDQpCb3RoIG1hbGVzIGFuZCBmZW1hbGVzIHNob3cgc2ltaWxhciBwYXR0ZXJucyBpbiBleGVyY2lzZSBoYWJpdHMsIHdpdGggdGhlIGhpZ2hlc3QgY291bnQgaW4gImhpZ2ggZXhlcmNpc2UiIGFuZCBzaW1pbGFyIGRpc3RyaWJ1dGlvbnMgYWNyb3NzICJtZWRpdW0iIGFuZCAibG93IiBjYXRlZ29yaWVzLg0KDQpgYGB7cn0NCiMgUHJlcGFyaW5nIHBsb3QgZGF0YQ0KR2VuZGVyX0V4ZXJjaXNlIDwtIA0KICBkYXRhICU+JQ0KICBncm91cF9ieShHZW5kZXIsIEV4ZXJjaXNlLkhhYml0cykgJT4lDQogIHN1bW1hcmlzZShDb3VudCA9IG4oKSkNCg0KIyBHZW5lcmF0aW5nIHBsb3QNCkdFIDwtIHBsb3RfbHkoKQ0KR0UgPC0gR0UgJT4lIA0KICBhZGRfdHJhY2UoDQogICAgZGF0YSA9IHN1YnNldChHZW5kZXJfRXhlcmNpc2UsIEV4ZXJjaXNlLkhhYml0cyA9PSAiTG93IiksDQogICAgeCA9IH5HZW5kZXIsDQogICAgeSA9IH5Db3VudCwNCiAgICBuYW1lID0gIkxvdyINCiAgKSAlPiUgDQogIGFkZF90cmFjZSgNCiAgICBkYXRhID0gc3Vic2V0KEdlbmRlcl9FeGVyY2lzZSwgRXhlcmNpc2UuSGFiaXRzID09ICJNZWRpdW0iKSwNCiAgICB4ID0gfkdlbmRlciwNCiAgICB5ID0gfkNvdW50LA0KICAgIG5hbWUgPSAiTWVkaXVtIg0KICApICU+JQ0KICBhZGRfdHJhY2UoDQogICAgZGF0YSA9IHN1YnNldChHZW5kZXJfRXhlcmNpc2UsIEV4ZXJjaXNlLkhhYml0cyA9PSAiSGlnaCIpLA0KICAgIHggPSB+R2VuZGVyLA0KICAgIHkgPSB+Q291bnQsDQogICAgbmFtZSA9ICJIaWdoIg0KICApICU+JSANCiAgbGF5b3V0KA0KICAgIHRpdGxlID0gIkdlbmRlciBhbmQgRXhlcmNpc2UgSGFiaXRzIiwNCiAgICB4YXhpcyA9IGxpc3QodGl0bGUgPSAiR2VuZGVyIiksDQogICAgeWF4aXMgPSBsaXN0KHRpdGxlID0gIkNvdW50IiksDQogICAgbGVnZW5kID0gbGlzdCgNCiAgICAgIHRpdGxlID0gbGlzdCh0ZXh0ID0gIjxiPiBFeGVyY2lzZSBIYWJpdHMgPC9iPiIpLA0KICAgICAgYmdjb2xvciA9ICIjRTJFMkUyIiwNCiAgICAgIGJvcmRlcmNvbG9yID0gIiNGRkZGRkYiLA0KICAgICAgYm9yZGVyd2lkdGggPSAyDQogICAgKQ0KICApDQoNCiMgT3V0cHV0dGluZyBwbG90DQpHRQ0KYGBgDQoNCiMjIGBBbGNvaG9sIENvbnN1bXB0aW9uYCBhbmQgYEhlYXJ0IERpc2Vhc2UgU3RhdHVzYA0KDQpNb3N0IGluZGl2aWR1YWxzIHdobyBjb25zdW1lIGFsY29ob2wgYXQgbG93LCBtZWRpdW0sIG9yIG5vIGxldmVscyBkbyBub3QgaGF2ZSBoZWFydCBkaXNlYXNlLiBIb3dldmVyLCB0aGUgbnVtYmVyIG9mIGluZGl2aWR1YWxzIHdpdGggaGVhcnQgZGlzZWFzZSBpcyBjb25zaXN0ZW50IGFjcm9zcyB0aGVzZSBjYXRlZ29yaWVzLg0KDQpgYGB7cn0NCiMgUHJlcGFyaW5nIHBsb3QgZGF0YQ0KQWxjb2hvbF9IZWFydERpc2Vhc2UgPC0gDQogIGRhdGEgJT4lDQogIGdyb3VwX2J5KEFsY29ob2wuQ29uc3VtcHRpb24sIEhlYXJ0LkRpc2Vhc2UuU3RhdHVzKSAlPiUNCiAgc3VtbWFyaXNlKENvdW50ID0gbigpKQ0KDQojIEdlbmVyYXRpbmcgcGxvdA0KQUggPC0gcGxvdF9seSgpICU+JSANCiAgYWRkX3RyYWNlKA0KICAgIGRhdGEgPSBBbGNvaG9sX0hlYXJ0RGlzZWFzZSwNCiAgICB4ID0gfkFsY29ob2wuQ29uc3VtcHRpb24sIA0KICAgIHkgPSB+Q291bnQsIA0KICAgIHR5cGUgPSAiYmFyIiwNCiAgICBjb2xvciA9IH5IZWFydC5EaXNlYXNlLlN0YXR1cw0KICApICU+JSANCiAgbGF5b3V0KA0KICAgIHRpdGxlID0gIkFsY29ob2wgQ29uc3VtcHRpb24gYW5kIEhlYXJ0IERpc2Vhc2UgU3RhdHVzIiwNCiAgICB4YXhpcyA9IGxpc3QodGl0bGUgPSAiQWxjb2hvbCBDb25zdW1wdGlvbiIpLA0KICAgIHlheGlzID0gbGlzdCh0aXRsZSA9ICJDb3VudCIpLA0KICAgIGxlZ2VuZCA9IGxpc3QoDQogICAgICB0aXRsZSA9IGxpc3QodGV4dCA9ICI8Yj4gSGVhcnQgRGlzZWFzZSBTdGF0dXMgPC9iPiIpLA0KICAgICAgYmdjb2xvciA9ICIjRTJFMkUyIiwNCiAgICAgIGJvcmRlcmNvbG9yID0gIiNGRkZGRkYiLA0KICAgICAgYm9yZGVyd2lkdGggPSAyDQogICAgKQ0KICApDQoNCiMgT3V0cHV0dGluZyBwbG90DQpBSA0KYGBgDQoNCiMjIGBDaG9sZXN0ZXJvbCBMZXZlbGAsIGBUcmlnbHljZXJpZGUgTGV2ZWxgLCBhbmQgYEJNSWANCg0KVGhlIDNEIHNjYXR0ZXJwbG90IHNob3dzIG5vIGNsZWFyIGNsdXN0ZXJpbmcgb3IgcGF0dGVybiBhbW9uZyB0aGVzZSB0aHJlZSB2YXJpYWJsZXMuIEJNSSwgY2hvbGVzdGVyb2wsIGFuZCB0cmlnbHljZXJpZGVzIGFyZSBzcHJlYWQgd2lkZWx5IGFjcm9zcyBhbGwgcmFuZ2VzLg0KDQpgYGB7cn0NCiMgR2VuZXJhdGluZyBwbG90DQpDVEIgPC0gcGxvdF9seSgpICU+JSANCiAgYWRkX3RyYWNlKA0KICAgIGRhdGEgPSBkYXRhLA0KICAgIHggPSB+Q2hvbGVzdGVyb2wuTGV2ZWwsIA0KICAgIHkgPSB+VHJpZ2x5Y2VyaWRlLkxldmVsLCANCiAgICB6ID0gfkJNSSwNCiAgICBtYXJrZXIgPSBsaXN0KHNpemUgPSAyKSwNCiAgICBob3ZlcnRlbXBsYXRlID0gcGFzdGUoDQogICAgICAiPGI+Q2hvbGVzdGVyb2wgTGV2ZWw8L2I+OiAle3h9PGJyPiIsDQogICAgICAiPGI+VHJpZ2x5Y2VyaWRlIExldmVsPC9iPjogJXt5fTxicj4iLA0KICAgICAgIjxiPkJNSTwvYj46ICV7en0iDQogICAgKSwNCiAgICBuYW1lID0gIiINCiAgKSAlPiUNCiAgbGF5b3V0KA0KICAgIHRpdGxlID0gIkNob2xlc3Rlcm9sIExldmVsLCBUcmlnbHljZXJpZGUgTGV2ZWwsIGFuZCBCTUkiLA0KICAgIHNjZW5lID0gbGlzdCgNCiAgICAgIHhheGlzID0gbGlzdCh0aXRsZSA9ICJDaG9sZXN0ZXJvbCBMZXZlbCIpLA0KICAgICAgeWF4aXMgPSBsaXN0KHRpdGxlID0gIlRyaWdseWNlcmlkZSBMZXZlbCIpLA0KICAgICAgemF4aXMgPSBsaXN0KHRpdGxlID0gIkJNSSIpLA0KICAgICAgYXNwZWN0bW9kZSA9ICJjdWJlIg0KICAgICkNCiAgKQ0KDQojIE91dHB1dHRpbmcgcGxvdA0KQ1RCDQpgYGANCg0KDQoNCg0K